#!/usr/bin/env python

from formatter import NullFormatter
from HTMLParser import HTMLParser
from Pmltags import PmlTag, TagFactory
import inspect

class ParseError(Exception):
	def __init__(self, message):
		self.message = message
		
	def __str__(self):
		return self.message

class NearestTagStack(object):
	"""A stack which makes possible to find the last pushed tag of a specific name"""
	def __init__(self):
		self._stack = []
		
	def push(self, tag):
		self._stack.append(tag)
		
	def pop(self):
		return self._stack.pop()
		
	def top(self):
		try: return self._stack[-1]
		except:	return None
		
	def purge(self):
		self._stack = []
		
class Parser(HTMLParser):
	def __init__(self, code, dest, backend, verbose=0):
		HTMLParser.__init__(self)
		self._backend = backend
		self._dest = dest
		self._verbose = verbose
		
		self._doc = backend.Document(dest)
		self._tagstack = NearestTagStack()
		self._pagesize = 'A4'
		self._code = code
	
	def run(self):
		self._tagstack.purge()
		self._tagstack.push(TagFactory.Create('MAIN', []))
		print "PARSING..."
		self.feed(self._code)

	def handle_data(self, data):
		if not len("".join(data.split())):
			return
			
		try: last_tag = self._tagstack.top()
		except: raise IndexError, "simple text outside a tag"
		
		self._tagstack.top().add(data)
		
	def handle_startendtag(self, tag, attrs):
		if self._verbose: print "INLINE TAG:",tag
		
		if tag == 'document':
			for key,value in attrs:
				if key.lower() == 'size':
					self._pagesize = value.upper()
				elif key.lower() == 'unit':
					self._backend.Document.set_unit(value.upper())
		else:
			self._tagstack.top().add(TagFactory.Create(tag, attrs))
			
	def handle_starttag(self, tag, attrs):
		if self._verbose: print "OPENING:",tag
		
		self._tagstack.push(TagFactory.Create(tag, attrs))
			
	def handle_endtag(self, tag):
		if self._verbose: print "CLOSING:",tag
		
		last_opened_tag = self._tagstack.top()
		if last_opened_tag.name() != tag:
			raise ParseError,"Ending a tag which isn't the last opened one: "+str(tag)+" at position  "+str(self.getpos())+" expecting "+last_opened_tag.name()
		
		ctop = self._tagstack.pop()
		self._tagstack.top().add(ctop)
		
	def save_document(self):
		print "GENERATING PDF OF TYPE",self._pagesize,":",self._dest
		
		if self._tagstack.top().name() != 'MAIN':
			raise ParseError,"Some tag is still pending into the stack:"+self._tagstack.top().name()
			
		if self._verbose: print self._tagstack.top()
		
		self._tagstack.top().generateObject(self._backend, self._doc)
		self._doc.generate(self._pagesize)
		
		print "DONE"
	
if __name__ == "__main__":
	import PdfBackend
	import sys

	src_name = sys.argv [ 1 ]
	out_name = sys.argv [ 2 ]

	p = Parser( file ( src_name ).read (), out_name, PdfBackend, 1 )
	p.run()
	p.save_document()
